#ifndef ENDIAN_H
#define ENDIAN_H

//   检测平台的Endian
#include <type_traits>
#include <stdint.h>

#include <QDebug>
#define debugx1 qDebug().noquote() <<__FILE__<<__LINE__ <<Q_FUNC_INFO
#define debugx(...) do{debugx1;qDebug(__VA_ARGS__);}while(0)

//inline void debugx(){}
//inline void debugx(const char *msg, ...){}

typedef union uEndianTest{
    long value;
    struct
    {
        bool flittle_endian;
        bool fill[3];
    };
}EndianTest;
static const EndianTest __Endian_Test__ = { (long)1 };
const bool platform_little_endian = __Endian_Test__.flittle_endian;

//这样使用这个 platform_little_endian 就可以检测到当前平台是否是little_endian

/*
   Endian 转换(64位, 32位和16位的字节序转换)
   中间使用了异或交换的算法
   使用方法举例:
   long lValue = 0xff000000;
   ConvertEndian32( &lValue );
*/
inline void ConvertEndian64( void* lpMem )
{
    char * p = (char*)lpMem;
    p[0] = p[0] ^ p[7];
    p[7] = p[0] ^ p[7];
    p[0] = p[0] ^ p[7];

    p[1] = p[1] ^ p[6];
    p[6] = p[1] ^ p[6];
    p[1] = p[1] ^ p[6];

    p[2] = p[2] ^ p[5];
    p[5] = p[2] ^ p[5];
    p[2] = p[2] ^ p[5];

    p[3] = p[3] ^ p[4];
    p[4] = p[3] ^ p[4];
    p[3] = p[3] ^ p[4];
}

inline void ConvertEndian32( void* lpMem )
{
    char * p = (char*)lpMem;
    p[0] = p[0] ^ p[3];
    p[3] = p[0] ^ p[3];
    p[0] = p[0] ^ p[3];
    p[1] = p[1] ^ p[2];
    p[2] = p[1] ^ p[2];
    p[1] = p[1] ^ p[2];
}

inline void ConvertEndian16( void* lpMem )
{
    char * p = (char*)lpMem;
    p[0] = p[0] ^ p[1];
    p[1] = p[0] ^ p[1];
    p[0] = p[0] ^ p[1];
}
/*
union EndianConverter {
    uint16_t value;
    uint8_t bytes[2];
};
uint16_t convertEndian(uint16_t value) {
    EndianConverter converter;
    converter.value = value;
    // 交换字节顺序
    std::swap(converter.bytes[0], converter.bytes[1]);
    return converter.value;
}
*/
template<typename T>
typename std::enable_if<std::is_same<T, char>::value, T>::type
    inline EndianConvert(T t) {
//    debugx1<<"  EndianConvert -- char";
    return t;
}
template<typename T>
typename std::enable_if<std::is_same<T, int8_t>::value, T>::type
    inline EndianConvert(T t) {
    qDebug()<<"  EndianConvert -- int8_t";
    return t;
}
template<typename T>
typename std::enable_if<std::is_same<T, uint8_t>::value, T>::type
    inline EndianConvert(T t) {
    qDebug()<<"  EndianConvert -- uint8_t";
    return t;
}
template<typename T>
typename std::enable_if<std::is_same<T, int16_t>::value, T>::type
    inline EndianConvert(T t) {
    debugx1<<"  EndianConvert -- int16_t";
    if(!platform_little_endian)return t;
    T a=t;
    ConvertEndian16(&a);
    return a;
}
template<typename T>
typename std::enable_if<std::is_same<T, uint16_t>::value, T>::type
    inline EndianConvert(T t) {
    debugx1<<"  EndianConvert -- uint16_t";
    if(!platform_little_endian)return t;
    T a=t;
    ConvertEndian16(&a);
    return a;
}
template<typename T>
typename std::enable_if<std::is_same<T, int32_t>::value, T>::type
    inline EndianConvert(T t) {
    debugx1<<"  EndianConvert -- int32_t";
    if(!platform_little_endian)return t;
    T a=t;
    ConvertEndian32(&a);
    return a;
}
template<typename T>
typename std::enable_if<std::is_same<T, uint32_t>::value, T>::type
    inline EndianConvert(T t) {
    if(!platform_little_endian)return t;
    T a=t;
    ConvertEndian32(&a);
    return a;
}
template<typename T>
typename std::enable_if<std::is_same<T, int64_t>::value, T>::type
    inline EndianConvert(T t) {
    if(!platform_little_endian)return t;
    T a=t;
    ConvertEndian64(&a);
    return a;
}
template<typename T>
typename std::enable_if<std::is_same<T, uint64_t>::value, T>::type
    inline EndianConvert(T t) {
    if(!platform_little_endian)return t;
    T a=t;
    ConvertEndian64(&a);
    return a;
}
template<typename T>
typename std::enable_if<std::is_same<T, float>::value, T>::type
    inline EndianConvert(T t) {
    return t;
}
template<typename T>
typename std::enable_if<std::is_same<T, double>::value, T>::type
    inline EndianConvert(T t) {
    return t;
}

#endif // ENDIAN_H
